'''
@author: nick mueller
'''

import threading
import subprocess
import logging
from google.protobuf.internal import encoder

def getDelimitMessage(message):
    ''' returns a delimit message of the argument string '''
    # delimit the message by length
    mes = message.SerializeToString()
    delimt = encoder._VarintBytes(len(mes)) 
    return delimt + mes

_logger = None
def getLogger():
    ''' returns the logger instance for this application '''
    global _logger
    if( _logger == None ):
        _logger = logging.getLogger('TLC')
        hdlr = logging.FileHandler('./tlc.log')
        hdlr.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
        _logger.addHandler(hdlr)
        _logger.setLevel(logging.INFO)
        
    return _logger

def parallelExec(command):
    ''' tries to execute the command argument in a new thread '''
    op = ParallelOperation(printExecer, command)
    op.start()

    # wait for thread ending
    # op.join()

def printExecer(command):
    ''' tries to execute the command argument and redirects the output in logfile '''
    proc = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
    out = proc.communicate()
    getLogger().info(out[0].rstrip('\n'))
    return proc

   
class ParallelOperation(threading.Thread):
    '''
    The ParallelOperation is based on the Thread class and runs
    function pointer in a new thread. Moreover it is possible to
    define listeners for before and after the main execution.
    '''
    def __init__(self, operation, *opArgs):
        threading.Thread.__init__(self)
        self._before = None;
        self._beforeArgs = None;
        
        self._after = None;
        self._afterArgs = None
        
        self._op = operation;
        self._opArgs = opArgs;

    def setBeforeFunc(self, beforeFunc, *args):
        self._before = beforeFunc;
        self._beforeArgs = args;

    def setAfterFunc(self, afterFunc, *args):
        self._after = afterFunc;
        self._afterArgs = args;

    def run(self):
        if(not(self._before == None)):
            self._before(*self._beforeArgs)
        
        self._op(*self._opArgs)

        if(not(self._after == None)):
            self._after(*self._afterArgs)


class ParallelExecOperation(ParallelOperation):
    ''' 
    The ParallelExecOperation is a special ParallelOperation an uses
    the printExecer for the main execution. This is why this class
    only needs the exec command by init.
    '''
    def __init__(self, operation):
        ParallelOperation.__init__(self, printExecer, operation)
